using System;
using System.Collections;
using System.IO;
using System.Xml.Serialization;

namespace TVListings
{
	public class TVGuide
	{
		string LocaleLanguage = "en";
		TVListing listing;
		Hashtable channelIDs;
		ArrayList channels;
		Hashtable programsByChannel;
		Hashtable categories;
		DateTime earliest;
		DateTime latest;
		/// TODO: Add search by actor, keyword, etc.

		public TVGuide()
		{
			listing = null;
			channelIDs = new Hashtable();
			channels = new ArrayList();
			programsByChannel = new Hashtable();
			categories = new Hashtable();
			latest = DateTime.MinValue;
			earliest = DateTime.MaxValue;
		}

		public void LoadListings(string Filename)
		{
			channelIDs.Clear();
			channels.Clear();
			programsByChannel.Clear();
			categories.Clear();

			XmlSerializer serializer = new XmlSerializer(typeof(TVListing));
			StreamReader file = File.OpenText(Filename);
			listing = (TVListing)serializer.Deserialize(file);
			file.Close();

			OrganizeListings();
		}
		
		public static TVGuide FromFile(string Filename)
		{
			TVGuide g = new TVGuide();
			g.LoadListings(Filename);
			return g;
		}

		void OrganizeListings()
		{
			foreach (Channel c in listing.Channels)
			{
				channelIDs.Add(c.ID, c);
				channels.Add(c);
				programsByChannel.Add(c.ID, new ArrayList());
			}

			foreach (Program p in listing.Programs)
			{
				AddToList(programsByChannel, p.ChannelID, p);

				if (p.Category != null)
					foreach (Descriptor d in p.Category)
						if (d.Language == LocaleLanguage)
							AddToList(categories, d.Value, p);

				if (p.Ratings != null)
					foreach (Rating r in p.Ratings)
						// Heuristic to find movies - may miss some
						if (r.System == "MPAA")
							AddToList(categories, "Movie", p);
				
				if (p.Start < earliest)
					earliest = p.Start;
				if (p.Stop > latest)
					latest = p.Stop;
			}

			channels.Sort();
			foreach (ArrayList l in programsByChannel.Values)
				l.Sort();
			foreach (ArrayList l in categories.Values)
				l.Sort();
		}

		void AddToList(Hashtable Table, object Identifier, object Object)
		{
			if (!Table.Contains(Identifier))
				Table.Add(Identifier, new ArrayList());
			((ArrayList)Table[Identifier]).Add(Object);
		}

		public Channel[] Channels
		{
			get { return (Channel[])channels.ToArray(typeof(Channel)); }
		}

		public Program[] GetProgramsByChannel(string ChannelID)
		{
			if (!programsByChannel.Contains(ChannelID))
				return new Program[0];

			return (Program[])((ArrayList)programsByChannel[ChannelID]).ToArray(typeof(Program));
		}

		public Program[] GetProgramsByCategory(string Category)
		{
			if (!categories.Contains(Category))
				return new Program[0];

			return (Program[])((ArrayList)categories[Category]).ToArray(typeof(Program));
		}

		public Program[] Programs
		{
			get { return listing.Programs; }
		}

		public Channel GetChannel(string ChannelID)
		{
			if (!channelIDs.Contains(ChannelID))
				return null;

			return (Channel)channelIDs[ChannelID];
		}
		
		public string[] GetCategories()
		{
			ArrayList c = new ArrayList();
			
			foreach (DictionaryEntry de in categories)
				c.Add(de.Key);
			
			return (string[])c.ToArray(typeof(string));
		}
		
		public bool IsMovie(Program p)
		{
			return ((ArrayList)categories["Movie"]).Contains(p);
		}
		
		public DateTime StartTime
		{
			get { return earliest; }
		}
		
		public DateTime StopTime
		{
			get { return latest; }
		}
	}
}
